<html>

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width,initial-scale=1.0" />
  <script src="https://unpkg.com/vue@next"></script>
  <title>虚拟列表</title>
  <style>
    .container {
      display: flex;
      border: 1px solid;
      overflow-y: auto;
      height: var(--containerHeight);
    }

    .scroll-blank {
      height: var(--height);
    }

    .scroll {
      margin-top: var(--marginTop);
    }

    .scroll-item {
      height: var(--itemHeight);
      /* background-color: pink; */
    }
  </style>
</head>

<body>
  <div id="app">
    <div ref='container' class="container" :style="{
          '--containerHeight': containerHeight + 'px',
          '--height': height + 'px',
          '--itemHeight': itemHeight + 'px',
          '--marginTop': marginTop + 'px',
        }">
      <div class="scroll-blank"></div>
      <div class="scroll">
        <div v-for='(item, index) in activeList' :key='item' class="scroll-item">{{ item }}</div>
      </div>
    </div>
  </div>
  <script>
    const {
      computed,
      onMounted,
      ref
    } = Vue

    const createList = () => {
      const list = []

      let i = 0
      while (i < 1000) {
        list.push(i++)
      }

      return list
    }
    const App = {
      setup() {
        // container获取的dom对象
        const container = ref(null)

        // 下面4个为静态数据
        const list = createList()
        const containerHeight = 600
        const itemHeight = 20
        const height = list.length * itemHeight

        // start和marginTop 是动态数据
        let start = ref(0)
        let marginTop = ref(0)

        // 当前激活的list元素，一次行获取30条
        const activeList = computed(() => {
          const index = start.value
          return list.slice(index, index + 30)
        })

        onMounted(() => {
          container.value.addEventListener('scroll', ({
            target
          }) => {
            const {
              scrollTop
            } = target
            const itemNum = scrollTop / itemHeight
            // 更新start 的数据
            start.value = parseInt(itemNum)
            // 更新marginTop数据
            marginTop.value = scrollTop
          })
        })

        return {
          container,
          marginTop,
          containerHeight,
          height,
          itemHeight,
          activeList
        }
      }
    };

    const app = Vue.createApp(App);
    app.mount("#app");
  </script>
</body>

</html>